
`timescale 1 ns / 1 ps

	module axis_data_merger_v1_0 #
	(
	  parameter SLAVE_AXIS_NUM = 2,
      parameter AUTO_RESET_FIFO = 0,
      parameter ALL_DATA_WIDTH = 2,
      parameter ADD_DATA_FLAG = 0,
      parameter USE_TUSER = 0
   
)(
    input  wire       m_clk,
    input  wire       m_aresetn,
    output wire[31:0] m_tdata,
    input  wire       m_tready,
    output wire       m_tvalid,
    output wire[3:0]  m_tkeep,
    output reg[2:0]   m_tuser,
    output wire       fifo_resetn_out,

    input wire[31:0] s0_axis_tdata,
    input wire[31:0] s1_axis_tdata,
    input wire[31:0] s2_axis_tdata,
    input wire[31:0] s3_axis_tdata,
    input wire[31:0] s4_axis_tdata,
    input wire[31:0] s5_axis_tdata,
    input wire[31:0] s6_axis_tdata,

    input wire       s0_axis_tvalid,
    input wire       s1_axis_tvalid,
    input wire       s2_axis_tvalid,
    input wire       s3_axis_tvalid,
    input wire       s4_axis_tvalid,
    input wire       s5_axis_tvalid,
    input wire       s6_axis_tvalid,

    output wire       s0_axis_tready,
    output wire       s1_axis_tready,
    output wire       s2_axis_tready,
    output wire       s3_axis_tready,
    output wire       s4_axis_tready,
    output wire       s5_axis_tready,
    output wire       s6_axis_tready
 
);

wire[6:0] state[7:0];
assign state[0] = 7'b0000_001;
assign state[1] = 7'b0000_010;
assign state[2] = 7'b0000_100;
assign state[3] = 7'b0001_000;
assign state[4] = 7'b0010_000;
assign state[5] = 7'b0100_000;
assign state[6] = 7'b1000_000;
assign state[7] = 7'b0000_001;

reg[6:0] curState;

wire[6:0] data_valid;
reg[6:0] valid;
reg[6:0] ready;
reg[31:0] readed_count;
reg can_load_data;
reg data_loaded;

assign data_valid = {s6_axis_tvalid, s5_axis_tvalid, s4_axis_tvalid, s3_axis_tvalid, s2_axis_tvalid, s1_axis_tvalid, s0_axis_tvalid};
assign {s6_axis_tready, s5_axis_tready, s4_axis_tready, s3_axis_tready, s2_axis_tready, s1_axis_tready, s0_axis_tready} = ready;

localparam FIFOED_MAX = SLAVE_AXIS_NUM * (2048 / SLAVE_AXIS_NUM) - 2;


wire[31:0] s_data[6:0];
assign s_data[0] = s0_axis_tdata; 
assign s_data[1] = s1_axis_tdata;
assign s_data[2] = s2_axis_tdata;
assign s_data[3] = s3_axis_tdata;
assign s_data[4] = s4_axis_tdata;
assign s_data[5] = s5_axis_tdata;
assign s_data[6] = s6_axis_tdata;

wire[3:0] flag[6:0];

assign flag[0] = 3'b001;
assign flag[1] = 3'b010;
assign flag[2] = 3'b011;
assign flag[3] = 3'b100;
assign flag[4] = 3'b101;
assign flag[5] = 3'b110;
assign flag[6] = 3'b111;

reg [31:0]  fs_tdata;
wire        fs_tvalid;
wire        fs_tready;
//reg         fm_tlast;  

//assign m_tlast = fm_tlast;

wire        fifo_rst;
reg         fifo_reset;     
wire[31:0]  fifo_write_counter;
assign fifo_resetn_out = fifo_reset;

assign fifo_rst = fifo_reset & m_aresetn;
assign fs_tvalid = data_loaded;

reg[3:0] tkeep;
reg[31:0] f_data;
assign m_tkeep = m_tvalid ? tkeep : 4'b0000;

always @(*) begin
    case (ALL_DATA_WIDTH)
       2 : tkeep = 4'b0011;
       3 : tkeep = 4'b0111;
       4 : tkeep = 4'b1111;
        default: tkeep = 4'b1111;
    endcase
    case (ALL_DATA_WIDTH)
       2 : f_data = fs_tdata[31:16];
       3 : f_data = fs_tdata[31:8];
       4 : f_data = fs_tdata[31:0];
        default: f_data = fs_tdata[31:0];
    endcase
end

always @(negedge m_clk or negedge m_aresetn) begin
    if (!m_aresetn) begin
        can_load_data <= 0;
    end else if (fs_tready == 1) begin
        can_load_data <= 1;
    end else if(data_loaded == 1) begin
        can_load_data <= 0;
    end else begin
        can_load_data <= can_load_data;
    end
end

integer i;
always @(posedge m_clk or negedge m_aresetn) begin
    if (!m_aresetn) begin
        fs_tdata <= 0;
        data_loaded <= 0;
        ready <= 0;
        m_tuser <= 0;
    end else if(can_load_data) begin
        for (i = 0; i < SLAVE_AXIS_NUM; i = i + 1) begin
            if (curState == state[i]) begin
                if (data_valid[i] && fifo_rst == 1 && fs_tready == 1) begin
                    ready <= state[i];
                    if(ADD_DATA_FLAG)begin
                        if (USE_TUSER) begin
                            fs_tdata <= s_data[i];
                            m_tuser <= flag[i];                             
                        end else begin
                            fs_tdata <= {5'b0000_0, flag[i], s_data[i][23:0]};
                            m_tuser <= 0;
                        end
                    end else begin
                        fs_tdata <= s_data[i];
                        m_tuser <= 0;
                    end
                    data_loaded <= 1;
                end else begin
                    ready <= 0;
                    fs_tdata <= fs_tdata;
                    m_tuser <= m_tuser;
                    data_loaded <= 0;
                end
            end
        end
    end else begin
        ready <= 0;
        fs_tdata <= fs_tdata;
        m_tuser <= 0;
        data_loaded <= data_loaded;
    end
end

integer j;
always @(negedge m_clk or negedge m_aresetn) begin
    if (!m_aresetn) begin
        curState <= state[0];
    end else if(fs_tready == 1 && data_loaded == 1) begin
         if (fifo_reset == 0) begin
            curState <= state[0];
         end else begin
            for (j = 0; j < SLAVE_AXIS_NUM; j = j + 1) begin
                if (curState == state[j]) begin
                    curState <= j == (SLAVE_AXIS_NUM - 1) ? state[0] : state[j + 1];
                end 
            end
         end
    end else begin
        curState <= curState;
    end
end

always @(posedge m_clk or negedge m_aresetn) begin
    if (!m_aresetn || AUTO_RESET_FIFO == 0) begin
        fifo_reset <= 1;
    end else if(fifo_write_counter == 0) begin
        fifo_reset <= 1;
    end else if(fifo_write_counter >= FIFOED_MAX && m_tready == 0 && curState == state[0])begin
        fifo_reset <= 0;
    end else begin
        fifo_reset <= fifo_reset;
    end
end

CONV_FIFO u_axis_data_fifo_0(
    .s_axis_aresetn     (fifo_rst           ),
    .s_axis_aclk        (m_clk              ),
    .s_axis_tvalid      (fs_tvalid          ),
    .s_axis_tready      (fs_tready          ),
    .s_axis_tdata       (f_data              ),
    .m_axis_tvalid      (m_tvalid            ),
    .m_axis_tready      (m_tready           ),
    .m_axis_tdata       (m_tdata            ),
    .axis_wr_data_count (fifo_write_counter )
);


endmodule